package com.example.hospital.ExceptionHandler;

import com.example.hospital.common.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.servlet.HandlerMapping;
import jakarta.validation.ConstraintViolationException;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     *  参数校验失败
     * @param request
     * @param ex
     * @return
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ApiResponse<Object>> handleIllegalArgument(HttpServletRequest request, IllegalArgumentException ex) {
        boolean namedValueResolutionError = Arrays.stream(ex.getStackTrace()).anyMatch(el ->
                "org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver".equals(el.getClassName())
                        && "updateNamedValueInfo".equals(el.getMethodName()));

        String uri = request.getRequestURI();
        String method = request.getMethod();

        Object handlerAttr = request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE);
        String handlerSignature = null;
        if (handlerAttr instanceof HandlerMethod hm) {
            Method m = hm.getMethod();
            handlerSignature = hm.getBeanType().getName() + "#" + m.getName() + "(" +
                    Arrays.stream(m.getParameters())
                            .map(p -> p.getType().getSimpleName() + " " + p.getName())
                            .collect(Collectors.joining(", ")) + ")";
        }

        if (namedValueResolutionError) {
            log.error("NamedValue resolution error on {} {} -> handler: {}: {}", method, uri, handlerSignature, ex.getMessage());
            return ResponseEntity.badRequest().body(ApiResponse.error(-400, "Invalid request parameter: " + ex.getMessage()));
        }

        log.error("IllegalArgumentException on {} {} -> handler: {}", method, uri, handlerSignature, ex);
        return ResponseEntity.badRequest().body(ApiResponse.error(-400, ex.getMessage()));
    }

    /**
     * 参数校验失败
     * @param request
     * @param ex
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ApiResponse<Object>> handleMethodArgumentNotValid(HttpServletRequest request, MethodArgumentNotValidException ex) {
        String uri = request.getRequestURI();
        String method = request.getMethod();
        List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
        String msg = fieldErrors.stream()
                .map(e -> e.getField() + ": " + (e.getDefaultMessage() == null ? "invalid" : e.getDefaultMessage()))
                .collect(Collectors.joining("; "));
        log.warn("Validation failed on {} {}: {}", method, uri, msg);
        return ResponseEntity.badRequest().body(ApiResponse.error(-400, "参数校验失败: " + msg));
    }

    /**
     *  参数绑定失败
     * @param request
     * @param ex
     * @return
     */

    @ExceptionHandler(BindException.class)
    public ResponseEntity<ApiResponse<Object>> handleBindException(HttpServletRequest request, BindException ex) {
        String uri = request.getRequestURI();
        String method = request.getMethod();
        String msg = ex.getBindingResult().getFieldErrors().stream()
                .map(e -> e.getField() + ": " + (e.getDefaultMessage() == null ? "invalid" : e.getDefaultMessage()))
                .collect(Collectors.joining("; "));
        log.warn("BindException on {} {}: {}", method, uri, msg);
        return ResponseEntity.badRequest().body(ApiResponse.error(-400, "参数绑定失败: " + msg));
    }

    /**
     * 参数校验失败
     * @param request
     * @param ex
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<ApiResponse<Object>> handleConstraintViolation(HttpServletRequest request, ConstraintViolationException ex) {
        String uri = request.getRequestURI();
        String method = request.getMethod();
        String msg = ex.getConstraintViolations().stream()
                .map(cv -> {
                    String path = cv.getPropertyPath() == null ? "" : cv.getPropertyPath().toString();
                    String message = cv.getMessage();
                    return path + ": " + message;
                })
                .collect(Collectors.joining("; "));
        log.warn("ConstraintViolation on {} {}: {}", method, uri, msg);
        return ResponseEntity.badRequest().body(ApiResponse.error(-400, "参数校验失败: " + msg));
    }

    /**
     *  缺少参数
     * @param request
     * @param ex
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseEntity<ApiResponse<Object>> handleMissingParam(HttpServletRequest request, MissingServletRequestParameterException ex) {
        String uri = request.getRequestURI();
        String method = request.getMethod();
        log.warn("Missing request parameter on {} {}: {}", method, uri, ex.getMessage());
        String msg = "缺少必填参数: " + ex.getParameterName();
        return ResponseEntity.badRequest().body(ApiResponse.error(-400, msg));
    }

    /**
     * 请求体解析失败
     * @param request
     * @param ex
     * @return
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResponseEntity<ApiResponse<Object>> handleNotReadable(HttpServletRequest request, HttpMessageNotReadableException ex) {
        String uri = request.getRequestURI();
        String method = request.getMethod();
        String causeMsg = ex.getMostSpecificCause() != null ? ex.getMostSpecificCause().getMessage() : ex.getMessage();
        log.warn("HttpMessageNotReadable on {} {}: {}", method, uri, causeMsg);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.error(-400, "请求体解析失败: " + causeMsg));
    }

    /**
     * 请求方法不支持
     * @param request
     * @param ex
     * @return
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseEntity<ApiResponse<Object>> handleMethodNotSupported(HttpServletRequest request, HttpRequestMethodNotSupportedException ex) {
        String uri = request.getRequestURI();
        String method = request.getMethod();
        String supported = ex.getSupportedHttpMethods() == null ? "" : ex.getSupportedHttpMethods().stream().map(HttpMethod::name).collect(Collectors.joining(", "));
        log.warn("MethodNotSupported on {} {}: {}", method, uri, ex.getMessage());
        return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).body(ApiResponse.error(-405, "不支持的请求方法: " + ex.getMethod() + (supported.isEmpty() ? "" : ", 支持: " + supported)));
    }

    /**
     *  运行时异常
     * @param request
     * @param ex
     * @return
     */
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<ApiResponse<Object>> handleRuntimeException(HttpServletRequest request, RuntimeException ex) {
        String uri = request.getRequestURI();
        String method = request.getMethod();
        log.error("RuntimeException on {} {}", method, uri, ex);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ApiResponse.error(-500, "服务器内部错误"));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiResponse<Object>> handleException(HttpServletRequest request, Exception ex) {
        String uri = request.getRequestURI();
        String method = request.getMethod();
        log.error("Unhandled Exception on {} {}", method, uri, ex);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ApiResponse.error(-500, "服务器内部错误"));
    }
}